Photo by Riccardo Pelati on Unsplash
前言
First of all, thanks to teacher 吳哲宇 for making the course of 動畫互動網頁特效入門。
JavaScript has become the programming language of everything. While looking at the job market, you might find that the roles of ‘Front-end Developers’ are vastly different.
- Build B2B web products for automated production service among industries. In this area, 80% of your time is dealing with data and forms.
- Be a full stack developer forced by your company. (60% front-end plus 40% back-end or vise versa.)
- Master in HTML5 audio and video.
- Build cross-platform mobile apps with react-native or Ionic. But you should at least familiar with one native ecosystem - ios or android.
- Build interaction websites. CSS/SVG/canvas/webgl focused.
As a woman who loves beautiful things, I like to build fancy websites and much appreciate designer’s work. However, as I know the job market better, I realized 80% of job demands are type 1 and 2 above-mentioned. The need for the rest might less than 20%. Such an intervallic demand ratio might be normality, not only Taiwan but all over the world, otherwise the well-known ”web developer road map” would not be taken as a standard of front-end skill-map.
After following the “road map” for three years, I do not give up the path to beautiful and interactive websites. I started to learn Vue but scoped out another new field - canvas, at the same time.
Structure
In the beginning, I created two objects - a canvas object and a game object.
Both of them had three critical functions - initialize, update, and render. Just like those front-end frameworks, everything would initialize at first, then draw the picture and update data.
Canvas object
class Canvas {
init = () => {
// 1. use the new operator to create an instance of Game
this.game = new Game();
this.game.init();
// 2. draw the big picture
requestAnimationFrame(this.render);
// 3. update data
setInterval(this.update, 1000 / this.fps);
}
update = () => {
// call game.update
this.game.update();
}
render = () => {
// 1. remove all
ctx.clearRect();
// 2. call game.update to draw the new frame
this.game.render();
}
}
Create an instance of the Game object, and initialize all the data I need at the init stage. Meanwhile, render the big picture and update data continuously.
Game Object
Initialize
There would be one or two players in the game. In this stage, players’ default data, such as which character should be controlled by whom, would be determined. Besides, I randomly created different types of stairs and their coordinates.
Update
The stairs would ascend continuously and should be destroyed as they leave the game area.
The coordinates of the players were much more complicated. I captured the keyboard event from the player to decide each character’s movement and determined the character’s reaction with different types of stairs. For instance, hurt or bounce.
Render
The so-called “render” means “draw what you want to see.” You shouldn’t update any data at this stage.
As the data of the players and the stairs update continuously, I would keep rendering by removing everything that presented milliseconds ago and draw the new state of objects.
The most challenging part of my personal view was sculpturing a shaped object by JS. It requires knowledge of computer graphics and keeps translate the painting point. If the result was not what you expect without any error message, you must feel frustrated while debugging.
class Game {
init = () => {
// initialize players
this.createPlayers();
// initialize stairs
this.createStairs();
}
update = () => {
// update stair position and create new stairs
this.updateStairs();
// update players
this.updatePlayers();
}
render = () => {
// draw players
this.renderPlayers();
// draw stairs
this.renderStairs();
// draw player HP
this.renderPlayerHP();
// draw the blades on the roof
this.renderRoofBlade();
}
willUnmount = () => {
// stop the game
this.isPlaying = false;
}
}
WillUnmount
At this stage, I stopped updating all the data and removed the event listeners.
Stair Object
Every stair was an instance of the Stair object. By using the “new” operator and setting custom properties, each stair had its type and reaction.
All the stairs had two things in common: they went up by constant velocity(you could custom its speed of course) and marked as inactive while leaving the game. I modified these commonalities in the update stage.
In the render stage, the appearance of each stair customed by switching the stair type property.
class Stair {
update = () => {
// 1. keeps constant upward velocity
// 2. mark as inactive if the stair leaves the game area
}
render = () => {
// draw presence
switch (type) {
case "normal":
this.renderNormal();
break;
case "blade":
this.renderBlade();
break;
case "jump":
this.renderJump();
break;
case "fade":
this.renderFade();
break;
case "slideLeft":
this.renderSlide();
break;
case "slideRight":
this.renderSlide();
break;
default:
break;
}
}
}
Character Object
There were two players in the game. The player would have various reactions with the stair and keeps changing their position.
class Player {
init = () => {
// init player actions
}
update = () => {
// leA
}
render = () => {
// draw different actions
if (isHurt) {
// hurt
this.hurt();
return;
}
if (!isStepOnStair) {
// jump
this.jump();
} else {
if (isRunning) {
// run
this.run();
} else {
// stand
this.stand();
}
}
}
}
Initialize
Initialize the character movement animation by character ID. I will go further in the next chapter.
Update
The character would get gravity as she leaves the stair.
I decided whether the character was on the stair by calculating the character’s coordination with the border of each stair. There were at most 6 or 7 stairs at the same time, so I measured with for-loop.
Render
Default character movements were hurt, jump, run, and stand. By if/else statement, the specified actions would be rendered.
Next chapter, I will focus on how to draw character motions, and embed each movement to one canvas.
Summary
The image below is the whole structure of the game “Down Stairs.”
The life cycle - initialize, update, and render could apply to all the objects with a maintainable structure.